﻿
namespace Patterns4Net.Tests.Core
{
    using System;
    using System.Diagnostics.Contracts;
    using Mono.Cecil;
    using Moq;
    using NUnit.Framework;
    using Patterns4Net.Attributes;
    using Patterns4Net.Core;
    using Patterns4Net.Core.CecilExtensions;
    using Patterns4Net.Core.Patterns;

    [TestFixture]
    public class PatternsLocatorTest 
    {
        [Test]
        public void GetPatternsOf_Calls_Given_Provider_And_Returns_Its_Result() 
        {
            var pattern = new Pattern(1);
            var typeDefinition = this.GetType().GetTypeDefinition();
            Contract.Assume(typeDefinition != null);
            var providerMock = this.GetProviderMock(typeDefinition, pattern);
            var locator = new PatternsLocator(new[] { providerMock.Object });
            var result = locator.GetPatternsOf(typeDefinition);

            CollectionAssert.IsNotEmpty(result);
            CollectionAssert.AreEquivalent(new[] { pattern }, result);
        }

        [Test]
        public void GetPatternsOf_Merges_Results_Of_Given_Two_Providers() 
        {
            var pattern1 = new Pattern(1);
            var pattern2 = new Pattern(2);
            var typeDefinition = this.GetType().GetTypeDefinition();
            Contract.Assume(typeDefinition != null);
            var provider1 = this.GetProviderMock(typeDefinition, pattern1);
            var provider2 = this.GetProviderMock(typeDefinition, pattern2);
            var locator = new PatternsLocator(new[] { provider1.Object, provider2.Object });
            var result = locator.GetPatternsOf(typeDefinition);

            CollectionAssert.IsNotEmpty(result);
            CollectionAssert.AreEquivalent(new[] { pattern1, pattern2 }, result);
        }

        private Mock<IPatternsProvider> GetProviderMock(TypeDefinition parameter, IPattern patternBase) 
        {
            var provider = new Mock<IPatternsProvider>();
            provider.Setup(x => x.GetPatterns(parameter))
                .Returns(new[] { patternBase });
            return provider;
        }

        /// <summary>
        /// Dummy pattern implementation.
        /// Uses integer value to create different non equal patterns.
        /// </summary>
        private class Pattern : PatternBase
        {
            private readonly int discriminator;

            public Pattern(int discriminator) 
            {
                this.discriminator = discriminator;
            }

            public override bool Equals(object obj) 
            {
                return this.discriminator == ((Pattern)obj).discriminator;
            }

            public override int GetHashCode()
            {
                return this.discriminator;
            }
        }
    }
}
